/* * Copyright 2016 higherfrequencytrading.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package net.openhft.affinity.impl; import com.sun.jna.LastErrorException; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.PointerType; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.ptr.LongByReference; import net.openhft.affinity.IAffinity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.BitSet; /** * Implementation of {@link net.openhft.affinity.IAffinity} based on JNA call of * sched_SetThreadAffinityMask/GetProcessAffinityMask from Windows 'kernel32' library. Applicable for * most windows platforms * <p> * * * @author andre.monteiro */ public enum WindowsJNAAffinity implements IAffinity { INSTANCE; public static final boolean LOADED; private static final Logger LOGGER = LoggerFactory.getLogger(WindowsJNAAffinity.class); static { boolean loaded = false; try { INSTANCE.getAffinity(); loaded = true; } catch (UnsatisfiedLinkError e) { LOGGER.warn("Unable to load jna library", e); } LOADED = loaded; } private final ThreadLocal<Integer> THREAD_ID = new ThreadLocal<>(); @Override public BitSet getAffinity() { final CLibrary lib = CLibrary.INSTANCE; final LongByReference cpuset1 = new LongByReference(0); final LongByReference cpuset2 = new LongByReference(0); try { final int ret = lib.GetProcessAffinityMask(-1, cpuset1, cpuset2); // Successful result is positive, according to the docs // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683213%28v=vs.85%29.aspx if (ret <= 0) { throw new IllegalStateException("GetProcessAffinityMask(( -1 ), &(" + cpuset1 + "), &(" + cpuset2 + ") ) return " + ret); } long[] longs = new long[1]; longs[0] = cpuset1.getValue(); return BitSet.valueOf(longs); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } return new BitSet(); } @Override public void setAffinity(final BitSet affinity) { final CLibrary lib = CLibrary.INSTANCE; WinDef.DWORD aff; long[] longs = affinity.toLongArray(); switch (longs.length) { case 0: aff = new WinDef.DWORD(0); break; case 1: aff = new WinDef.DWORD(longs[0]); break; default: throw new IllegalArgumentException("Windows API does not support more than 64 CPUs for thread affinity"); } int pid = getTid(); try { lib.SetThreadAffinityMask(pid, aff); } catch (LastErrorException e) { throw new IllegalStateException("SetThreadAffinityMask((" + pid + ") , &(" + affinity + ") ) errorNo=" + e.getErrorCode(), e); } } public int getTid() { final CLibrary lib = CLibrary.INSTANCE; try { return lib.GetCurrentThread(); } catch (LastErrorException e) { throw new IllegalStateException("GetCurrentThread( ) errorNo=" + e.getErrorCode(), e); } } @Override public int getCpu() { return -1; } @Override public int getProcessId() { return Kernel32.INSTANCE.GetCurrentProcessId(); } @Override public int getThreadId() { Integer tid = THREAD_ID.get(); if (tid == null) THREAD_ID.set(tid = Kernel32.INSTANCE.GetCurrentThreadId()); return tid; } /** * @author BegemoT */ private interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) Native.loadLibrary("kernel32", CLibrary.class); int GetProcessAffinityMask(final int pid, final PointerType lpProcessAffinityMask, final PointerType lpSystemAffinityMask) throws LastErrorException; void SetThreadAffinityMask(final int pid, final WinDef.DWORD lpProcessAffinityMask) throws LastErrorException; int GetCurrentThread() throws LastErrorException; } }